<?php

namespace PhpYes\Modules\Aster;

use PhpYes\Com\ExtName;
use PhpYes\Yes;

class Asseter
{
    const EXT_DOT_JS = '.js';
    const EXT_DOT_CSS = '.css';
    const EXT_DOT_SASS = '.sass';
    const EXT_DOT_SCSS = '.scss';
    const EXT_WILD = '*';

    const MF_LATEST = 'latest';
    const MF_HISTORY = 'history';
    const MF_TS = 'ts';
    const MF_TIME = 'time';
    const MF_ASSETS = 'assets';

    const SHAPE_SRC = 'src';
    const SHAPE_OBJ = 'obj';
    const SHAPE_DIST = 'dist';
    const SHAPE_DIST_TAG = 'dist_tag';
    const SHAPE_DIST_MIN = 'dist_min';
    const SHAPE_DIST_TAG_MIN = 'dist_tag_min';

    // ----------

    /**
     * @return string
     */
    public function dist_dir()
    {
        return Yes::$p->public_dir();
    }

    /**
     * @param string $lib
     * @return string
     */
    public function lib_dist_dir($lib)
    {
        $lib = empty($lib) ? '' : trim($lib);
        return empty($lib) ? $this->dist_dir() : $this->dist_dir() . '/' . $lib;
    }

    // ----------

    /**
     * @return string
     */
    public function manifest_file()
    {
        return $this->lib_dist_dir('assets') . '/manifest.json';
    }

    protected $_manifest;

    /**
     * @return array
     */
    public function manifest()
    {
        if ($this->_manifest) {
            return $this->_manifest;
        }

        $file = $this->manifest_file();
        if (!is_file($file)) {
            return [];
        }

        $str = file_get_contents($file);
        $str = empty($str) ? '' : trim($str);
        if (empty($str)) {
            return [];
        }

        $json = @json_decode($str, true);
        $this->_manifest = empty($json) ? [] : $json;
        return $this->_manifest;
    }

    // ----------

    /**
     * 从 asset_id 中提取出 asset_lib
     * @param string $asset_id
     * @return string
     */
    public function asset_lib($asset_id)
    {
        $asset_id = empty($asset_id) ? '' : trim($asset_id);
        if (empty($asset_id)) {
            return '';
        }

        $idx = strpos($asset_id, '/');
        if ($idx === false) {
            return $asset_id;
        } else {
            return $idx > 0 ? substr($asset_id, 0, $idx) : '';
        }
    }

    /**
     * 拆解 asset_id 从而提取出 lib, path
     * @param string $asset_id
     * @return string[] - [lib, path] - 返回的 path 是相对路径
     */
    public function split_asset_id($asset_id)
    {
        $asset_id = empty($asset_id) ? '' : trim($asset_id);
        if (empty($asset_id)) {
            return ['', ''];
        }

        $lib = '';
        $path = '';
        $idx = strpos($asset_id, '/');
        if ($idx === false) {
            $lib = $asset_id;
        } else {
            $lib = $idx > 0 ? substr($asset_id, 0, $idx) : '';
            $path = $idx + 1 < strlen($asset_id) ? substr($asset_id, $idx + 1) : '';
        }
        return [$lib, $path];
    }

    /**
     * 构造 asset_id, src_id, dist_id
     * @param string $lib
     * @param string $path - 相对路径
     * @return string
     */
    public function make_asset_id($lib, $path)
    {
        $lib = isset($lib) ? trim($lib) : '';
        $path = isset($path) ? trim($path) : '';
        return $lib . '/' . $path;
    }

    // ----------

    /**
     * @param string $dist_dot_ext
     * @return string - SHAPE_XXX
     */
    public function url_shape($dist_dot_ext)
    {
        $dist_dot_ext = empty($dist_dot_ext) ? '' : trim($dist_dot_ext);
        if (empty($dist_dot_ext)) {
            return self::SHAPE_DIST_TAG;
        }
        return $dist_dot_ext == self::EXT_DOT_JS || $dist_dot_ext == self::EXT_DOT_CSS ? self::SHAPE_DIST_TAG_MIN : self::SHAPE_DIST_TAG;
    }

    /**
     * @return string
     */
    public function url_path_prefix()
    {
        return '/';
    }

    /**
     * !!! note : 运行时计算 url_path , 依赖 manifest
     * @param string $lib
     * @param string $dist_path
     * @param string $dist_dot_ext
     * @param string $shape - SHAPE_DIST, SHAPE_DIST_TAG, ...
     * @return string
     */
    public function url_path($lib, $dist_path, $dist_dot_ext = '', $shape = '')
    {
        $lib = empty($lib) ? '' : trim($lib);
        if (empty($lib)) {
            return '';
        }

        $dist_path = isset($dist_path) ? trim($dist_path) : '';
        if ($dist_path === '') {
            return '';
        }

        $dist_id = $lib . '/' . $dist_path;

        $shape = empty($shape) ? '' : trim($shape);
        if (empty($shape)) {
            $dist_dot_ext = empty($dist_dot_ext) ? '' : trim($dist_dot_ext);
            if (empty($dist_dot_ext)) {
                $dist_dot_ext = ExtName::dot_ext($dist_path);
            }
            $shape = $this->url_shape($dist_dot_ext);
        }
        if ($shape == self::SHAPE_DIST) {
            return $this->url_path_prefix() . $dist_id;
        }

        $manifest = $this->manifest();
        if (empty($manifest)) {
            return '';
        }

        $shape_path = empty($manifest[self::MF_LATEST][self::MF_ASSETS][$dist_id][$shape])
            ? ''
            : trim($manifest[self::MF_LATEST][self::MF_ASSETS][$dist_id][$shape]);
        return empty($shape_path) ? '' : $this->url_path_prefix() . $lib . '/' . $shape_path;
    }

    /**
     * !!! note : 运行时计算 url_path , 依赖 manifest
     * @param string $dist_id
     * @param string $dist_dot_ext
     * @param string $shape - SHAPE_DIST, SHAPE_DIST_TAG, ...
     * @return string
     */
    public function url_path_i($dist_id, $dist_dot_ext = '', $shape = '')
    {
        $dist_id = empty($dist_id) ? '' : trim($dist_id);
        if (empty($dist_id)) {
            return '';
        }

        $shape = empty($shape) ? '' : trim($shape);
        if (empty($shape)) {
            $dist_dot_ext = empty($dist_dot_ext) ? '' : trim($dist_dot_ext);
            if (empty($dist_dot_ext)) {
                $dist_dot_ext = ExtName::dot_ext($dist_id);
            }
            $shape = $this->url_shape($dist_dot_ext);
        }
        if ($shape == self::SHAPE_DIST) {
            return $this->url_path_prefix() . $dist_id;
        }

        $lib = $this->asset_lib($dist_id);
        $lib = empty($lib) ? '' : trim($lib);
        if (empty($lib)) {
            return '';
        }

        $manifest = $this->manifest();
        if (empty($manifest)) {
            return '';
        }

        $shape_path = empty($manifest[self::MF_LATEST][self::MF_ASSETS][$dist_id][$shape])
            ? ''
            : trim($manifest[self::MF_LATEST][self::MF_ASSETS][$dist_id][$shape]);
        return empty($shape_path) ? '' : $this->url_path_prefix() . $lib . '/' . $shape_path;
    }

}